﻿using System;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using InvestmentIntelligence.Logging.Core;

namespace Invest.DataBaseUpdater.Core
{
    public class CreateDbProcessor : BaseProcessor
    {
        private readonly SqlConnection oldConnection = new SqlConnection();
        public CreateDbProcessor(SqlConnection connection)
            : base(connection)
        {
            oldConnection = new SqlConnection(connection.ConnectionString);
            var builder = new SqlConnectionStringBuilder(connection.ConnectionString) { InitialCatalog = "master" };
            Connection = new SqlConnection(builder.ToString());
        }
        public void Process(string fileLocation = null)
        {
            CreateEmptyDataBase(fileLocation);
            CreateDataBaseSchema();
            new UpdateDbProcessor(Connection).Process();
        }

        private void CreateEmptyDataBase(string fileLocation)
        {
            OpenConnection();
            var commandText = GenerateCreateDataBaseCommand(fileLocation);
            var command = Connection.CreateCommand();
            command.CommandText = commandText;
            command.ExecuteNonQuery();
            Connection.Close();
            Connection = new SqlConnection(oldConnection.ConnectionString);
        }

        private string GenerateCreateDataBaseCommand(string fileLocation)
        {
            if (string.IsNullOrWhiteSpace(fileLocation))
            {
                const string comand = @"CREATE DATABASE {0}";
                return string.Format(comand, oldConnection.Database);
            }
            else
            {
                var folderPath = Path.GetFullPath(fileLocation);
                var dbFilePath = Path.Combine(folderPath, oldConnection.Database.Replace(" ", "_") + ".mdf");
                var logFilePath = Path.Combine(folderPath, oldConnection.Database.Replace(" ", "_") + "_log.ldf");
                const string comand = @"CREATE DATABASE {0} ON  PRIMARY 
                            ( NAME = N'{1}', FILENAME = N'{2}' , SIZE = 10MB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
                             LOG ON 
                            ( NAME = N'{1}_log', FILENAME = N'{3}' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)";
                return string.Format(comand, oldConnection.Database, oldConnection.Database.Replace(" ", "_"),
                    dbFilePath, logFilePath);
            }
        }

        private void CreateDataBaseSchema()
        {
            OpenConnection();
            var scriptFiles = Directory.GetFiles("CreateDataBaseScritps", "*.sql", SearchOption.TopDirectoryOnly).ToList();
            foreach (var scriptFile in scriptFiles)
            {
                string sqlQuery;
                string sqlHeader;
                bool skipTransaction;
                ReadSqlFromFile(scriptFile, out sqlQuery, out sqlHeader, out skipTransaction);

                if (string.IsNullOrWhiteSpace(sqlQuery))
                {
                    continue;
                }

                var command = Connection.CreateCommand();
                command.Connection = Connection;
                try
                {
                    var sqlComands = sqlQuery.Split(new[] { "GO\r\n", "GO ", "GO\t" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var cmdText in sqlComands)
                    {
                        try
                        {
                            command.CommandText = cmdText;
                            command.ExecuteNonQuery();
                        }
                        catch (SqlException ex)
                        {
                            if (ex.Number == 9982//Cannot use full-text search in user instance.
                                || ex.Number == 7609 //Full-Text Search is not installed, or a full-text component cannot be loaded.
                                )
                            {
                                Log.Error(ex.Message + Environment.NewLine + cmdText);
                                continue;
                            }
                            throw;
                        }
                        
                    }
                }
                catch (SqlException ex)
                {
                    throw new ApplicationException(
                        string.Format("Failed to process script: '{0}'.\r\n Error message: '{1}'", scriptFile, ex.Message), ex);
                }
            }
            Connection.Close();
        }

    }
}
